Analyse des AfD-Wahlerfolgs bei der Bundestagswahl 2021
1 Hintergrund
1.1 Relevanz des Themas
Die Bundestagswahl ist ein zentrales Ereignis für die Öffentlichkeit in Deutschland. In Anbetracht der hohen Relevanz dieses Ereignisses stellt sich die Frage, welche Faktoren die Ursache (oder zumindest Prädiktoren) der Wahlentscheidungen der Bürgerinnen und Bürger sind. Ist beispielsweise die Höhe der Arbeitslosigkeit in einem Wahlkreis ausschlaggebend, dass die eine oder andere Partei gewählt wird? Spielt die Altersverteilung eine Rolle? Der Ausländeranteil?
Die Analyse des Wahlerfolgs der Partei “Alternative für Deutschland” (AfD) ist in diesem Zusammenhang von besonderem Interesse, da ein Teil ihrer Wählis und Vertretis offenbar die Grundsätze deutscher Politik hinterfragt und vielleicht entgegensteht. So hat das Bundesamt für Verfassungsschutz Teilorganisationen der AfD zum Verdachtsfall für Rechtsextremismus eingestuft.
Die Relevanz der Analyse extremistischer Bewegungen begründet sich mit einem Blick in die deutsche Geschichte: Die (deutsche) Geschichte des 20. Jahrhunderts zeigt, dass rechtsextreme Bewegungen das Potenzial für katastrophale Entwicklungen und schlimmste Verbrechen haben.
Ziel und Gegenstand dieses Workshops ist es nicht, eine Meinung oder ein Urteil über die Einschätzung des Verfassungsschutzes oder der AfD zu treffen. Vielmehr ist vor dem genannten Hintergrund die Analyse, warum bzw. unter welchen Randbedingungen die AfD Stimmen auf sich zieht (bei der Bundestagswahl, BTW, 2021), von (potenziell) hohem gesellschaftlichem Interesse.
1.2 Hinweise
Ziel dieser Analyse ist es, grundlegende Methoden der Datenanalyse für eine angewandte Forschungsfrage bzw. eine Forschungsfrage von allgemeinem Interesse, vorzustellen bzw. einzuüben.
Es handelt sich um eine Analyse mit rein didaktischem Ziel.
Es sind keinerlei politische Aussagen mit dieser Analyse verbunden.
1.3 Forschungsfragen
Bei der BTW 2021, wie groß ist der AfD-Stimmenanteil, aggregiert pro Bundesland und deutschlandweit? Wie verteilt sich der Stimmenanteil der AfD?
Wie hängt der Wahlerfolg der AfD mit sozioökonomischen Indikatoren wie Arbeitslosigkeitsquote und Ausländeranteil zusammen?
Welche Rolle spielen die Besonderheiten der Bundesländer, über die sozioökonomischen Indikatoren im Hinblick auf den Zweitstimmenanteil der AfD?
Die Forschungsfragen sind deskriptiv in dem Sinne, dass sie keine Kausalfragen adressieren, sondern lediglich (statistische) Zusammenhänge.
2 IT-Setup
2.1 Dateien herunterladen
Am einfachsten: Laden Sie den Github-Projektordner für diesen Workshop herunter. Dann haben sie gleich alle nötigen Dateien in der gleichen Struktur, wie in dieser Rmd-Datei aufgeführt.
Wenn Sie auf den grünen Button (“Code”) klicken, können Sie den ganzen Projektordner herunterladen.
2.2 R-Pakete laden
Nicht vergessen, dass die R-Pakete installiert sein müssen.
library(tidyverse) # Datenjudo
library(sf) # Geo-Visualisierung
library(rstatix) # Deskriptive Statistiken
library(corrr) # Korrelationsmatrizen
library(gt) # HTML Tabellen
library(rstanarm) # Bayes-Modellierung
library(tictoc) # Messung der Rechenzeit
library(bayesplot) # Visualisierung von Bayes-Modellen2.3 Sonstige Vorbereitung
Anderes ggplot-Theme setzen:
theme_set(theme_minimal())3 Daten aufbereiten
3.1 Ökonomopolitische Strukturdaten
3.1.1 Daten einlesen
Die Strukturdaten sind vom Bundeswahlleiter zu beziehen; über diesen Link kommt man zu den Daten (CSV-Format).
Die Variablennamen sind hier erklärt.
d_str_file <- "https://bundeswahlleiter.de/dam/jcr/b1d3fc4f-17eb-455f-a01c-a0bf32135c5d/btw21_strukturdaten.csv"
d_str <- read_delim(d_str_file,
delim = ";",
escape_double = FALSE,
locale = locale(decimal_mark = ",",
grouping_mark = "."),
trim_ws = TRUE,
skip = 8) Hier sind die Namen der Spalten:
names(d_str)## [1] "Land"
## [2] "Wahlkreis-Nr."
## [3] "Wahlkreis-Name"
## [4] "Gemeinden am 31.12.2019 (Anzahl)"
## [5] "Fläche am 31.12.2019 (km²)"
## [6] "Bevölkerung am 31.12.2019 - Insgesamt (in 1000)"
## [7] "Bevölkerung am 31.12.2019 - Deutsche (in 1000)"
## [8] "Bevölkerung am 31.12.2019 - Ausländer/-innen (%)"
## [9] "Bevölkerungsdichte am 31.12.2019 (EW je km²)"
## [10] "Zu- (+) bzw. Abnahme (-) der Bevölkerung 2019 - Geburtensaldo (je 1000 EW)"
## [11] "Zu- (+) bzw. Abnahme (-) der Bevölkerung 2019 - Wanderungssaldo (je 1000 EW)"
## [12] "Alter von ... bis ... Jahren am 31.12.2019 - unter 18 (%)"
## [13] "Alter von ... bis ... Jahren am 31.12.2019 - 18-24 (%)"
## [14] "Alter von ... bis ... Jahren am 31.12.2019 - 25-34 (%)"
## [15] "Alter von ... bis ... Jahren am 31.12.2019 - 35-59 (%)"
## [16] "Alter von ... bis ... Jahren am 31.12.2019 - 60-74 (%)"
## [17] "Alter von ... bis ... Jahren am 31.12.2019 - 75 und mehr (%)"
## [18] "Bodenfläche nach Art der tatsächlichen Nutzung am 31.12.2019 - Siedlung und Verkehr (%)"
## [19] "Bodenfläche nach Art der tatsächlichen Nutzung am 31.12.2019 - Vegetation und Gewässer (%)"
## [20] "Fertiggestellte Wohnungen 2019 (je 1000 EW)"
## [21] "Bestand an Wohnungen am 31.12.2019 - insgesamt (je 1000 EW)"
## [22] "Wohnfläche am 31.12.2019 (je Wohnung)"
## [23] "Wohnfläche am 31.12.2019 (je EW)"
## [24] "PKW-Bestand am 01.01.2020 - PKW insgesamt (je 1000 EW)"
## [25] "PKW-Bestand am 01.01.2020 - PKW mit Elektro- oder Hybrid-Antrieb (%)"
## [26] "Unternehmensregister 2018 - Unternehmen insgesamt (je 1000 EW)"
## [27] "Unternehmensregister 2018 - Handwerksunternehmen (je 1000 EW)"
## [28] "Schulabgänger/-innen beruflicher Schulen 2019"
## [29] "Schulabgänger/-innen allgemeinbildender Schulen 2019 - insgesamt ohne Externe (je 1000 EW)"
## [30] "Schulabgänger/-innen allgemeinbildender Schulen 2019 - ohne Hauptschulabschluss (%)"
## [31] "Schulabgänger/-innen allgemeinbildender Schulen 2019 - mit Hauptschulabschluss (%)"
## [32] "Schulabgänger/-innen allgemeinbildender Schulen 2019 - mit mittlerem Schulabschluss (%)"
## [33] "Schulabgänger/-innen allgemeinblldender Schulen 2019 - mit allgemeiner und Fachhochschulreife (%)"
## [34] "Kindertagesbetreuung am 01.03.2020 - Betreute Kinder unter 3 Jahre (Betreuungsquote)"
## [35] "Kindertagesbetreuung am 01.03.2020 - Betreute Kinder 3 bis unter 6 Jahre (Betreuungsquote)"
## [36] "Verfügbares Einkommen der privaten Haushalte 2018 (EUR je EW)"
## [37] "Bruttoinlandsprodukt 2018 (EUR je EW)"
## [38] "Sozialversicherungspflichtig Beschäftigte am 30.06.2020 - insgesamt (je 1000 EW)"
## [39] "Sozialversicherungspflichtig Beschäftigte am 30.06.2020 - Land- und Forstwirtschaft, Fischerei (%)"
## [40] "Sozialversicherungspflichtig Beschäftigte am 30.06.2020 - Produzierendes Gewerbe (%)"
## [41] "Sozialversicherungspflichtig Beschäftigte am 30.06.2020 - Handel, Gastgewerbe, Verkehr (%)"
## [42] "Sozialversicherungspflichtig Beschäftigte am 30.06.2020 - Öffentliche und private Dienstleister (%)"
## [43] "Sozialversicherungspflichtig Beschäftigte am 30.06.2020 - Übrige Dienstleister und \"\"ohne Angabe\"\" (%)"
## [44] "Empfänger/-innen von Leistungen nach SGB II Oktober 2020 - insgesamt (je 1000 EW)"
## [45] "Empfänger/-innen von Leistungen nach SGB II Oktober 2020 - nicht erwerbsfähige Hilfebedürftige (%)"
## [46] "Empfänger/-innen von Leistungen nach SGB II Oktober 2020 - Ausländer/-innen (%)"
## [47] "Arbeitslosenquote Februar 2021 - insgesamt"
## [48] "Arbeitslosenquote Februar 2021 - Männer"
## [49] "Arbeitslosenquote Februar 2021 - Frauen"
## [50] "Arbeitslosenquote Februar 2021 - 15 bis 24 Jahre"
## [51] "Arbeitslosenquote Februar 2021 - 55 bis 64 Jahre"
## [52] "Fußnoten"
Es ist vielleicht praktisch, die Spaltennamen für spätere Verwendung in einer Textdatei abzuspeichern:
d_str_names <-
tibble(
var_name = names(d_str),
) %>%
mutate(id = row_number())
write_csv(d_str_names, "objects/d_str_names.csv")3.1.2 Daten aufbereiten
Die Spaltennamen sind etwas unhandlich. Formulieren wir lieber prägnanter:
names(d_str) <- paste0("V",1:ncol(d_str))
d_str2 <-
d_str %>%
select(state = V1,
area_nr = V2,
area_name = V3,
for_prop = V8,
pop_density = V9,
pop_move = V11,
income = V36,
unemp = V47) Sichern wir diese Daten in eine Datei:
write_csv(d_str2, file = "objects/d_str2.csv")Oder als Excel-Exitstrategie:
writexl::write_xlsx(d_str2, path = "objects/d_str2.xlsx")3.2 Wahlergebnisse
3.2.1 Daten einlesen
Die Daten sind vom Bundeswahlleiter zu beziehen. Unter diesem Link kommt man direkt zur CSV-Datei.
Eine Erklärung zu den Variablen findet sich hier.
elec_results_file <- "https://www.bundeswahlleiter.de/bundestagswahlen/2021/ergebnisse/opendata/csv/kerg2.csv"
elec_results <- read_delim(elec_results_file,
delim = ";",
escape_double = FALSE,
locale = locale(decimal_mark = ",",
grouping_mark = "."),
trim_ws = TRUE,
skip = 9
) Alternativ kann man die Datei selber herunterladen und im Verzeichnis der Rmd-Datei abspeichern. Man kann als CSV-Datei oder als XLSX-Datei abspeichern und dann in R importieren. Etwas nervig ist, dass das deutsche Excel (im Standard) keine Standard-CSV erstellt.
Hier nur bruchstückhaft dargestellt; so können Sie die Datendatei importieren:
elec_results <- read_csv("kerg2_aufbereitet.csv")
elec_results <- read_csv2("kerg2_aufbereitet.csv") # Deutsches Excel!
elec_results <- readxl::read_xlsx("kerg2_aufbereitet.xslx")kerg2_aufbereitet.csv meint, Sie haben die ersten paar Zeilen selber gelöscht und insgesamt dafür gesorgt, dass es eine schöne, maschinenfreundliche Datendatei ist.
Eine CSV-Datei, die mit dem deutschen Excel erstellt wurde, können Sie mit read_csv2(dateiname) einlesen.
Achtung: Excel schreibt manchmal in Ihre CSV-Datei auch ohne dass Sie auf Speichern klicken! Fragen Sie mich nicht, warum Excel sich diese Freiheit nimmt.
3.2.2 Daten aufbereiten
Konzentrieren wir uns auf die Zweitstimme, da die bei der BTW die entscheidende ist.
elec_results2 <-
elec_results %>%
select(Gebietsart, Gebietsnummer, Gebietsname, UegGebietsart, UegGebietsnummer, Gruppenart, Gruppenname, Stimme, Prozent, DiffProzentPkt) %>%
filter(Gruppenname == "AfD") %>%
filter(Stimme == 2)Im anderen Datensatz wird “Bundesgebiet” mit “Deutschland” bezeichnet. Um die beiden Datensätze im Weiteren zusammenfügen zu können, sollten jeweils die gleiche Bezeichnung (für das gleiche “Ding”, sprich Gesamtdeutschland) verwenden werden:
elec_results2 <-
elec_results2 %>%
mutate(Gebietsname = ifelse(Gebietsname == "Bundesgebiet",
"Deutschland",
Gebietsname))Sichern wir diese Daten in eine Datei:
write_csv(elec_results2, file = "objects/elec_results2.csv")Der Befehl könnte voraussetzen, dass der Ordner objects existiert. Alternativ können Sie auch einfach ins aktuelle Verzeichnis schreiben, das ist einfacher (aber nicht so aufgeräumt):
write_csv(elec_results2, file = "elec_results2.csv")4 Einfache, univariate Ergebnisse
4.1 Mittelwert des AfD-Wahlerfolgs
4.1.1 … über alle Bundesländer
Achtung! Alle Bundesländer werden in der folgenden Analyse gleich gewichtet!
elec_results2 %>%
filter(Gebietsart == "Land") %>%
summarise(AfD_mean = mean(Prozent))## # A tibble: 1 × 1
## AfD_mean
## <dbl>
## 1 12.1
4.1.2 … über Deutschland
elec_results2 %>%
filter(Gebietsart == "Bund") %>%
summarise(AfD_mean = mean(Prozent)) ## # A tibble: 1 × 1
## AfD_mean
## <dbl>
## 1 10.3
4.1.3 … über Wahlkreise
elec_results2 %>%
filter(Gebietsart == "Wahlkreis") %>%
summarise(AfD_mean = mean(Prozent, na.rm = T))## # A tibble: 1 × 1
## AfD_mean
## <dbl>
## 1 10.5
4.2 Wahlerfolg der AfD nach Bundesländern
elec_results2 %>%
filter(Gebietsart == "Land") %>%
select(Gebietsname, Prozent) %>%
mutate(Gebietsname = as.factor(Gebietsname)) %>%
ggplot(aes(x = reorder(Gebietsname, Prozent),
y = Prozent)) +
geom_col() +
coord_flip() +
labs(title = "AfD-Zweitstimmenanteil bei der BTW 21",
caption = "Die Linie zeigt den Mittelwert für ganz Deutschland",
y = "Anteil in Prozent",
x = "Bundesländer") +
geom_hline(yintercept = 10.1) +
annotate("label", x = "Hamburg", y = 10,
label = "Mittelwert",
size = 2) +
geom_text(aes(label = round(Prozent)),
nudge_y = -1,
color = "white",
size = 2)5 Daten zusammenführen (join)
Mit einem “Join” lassen sich Tabellen zeilenweise zusammenführen. Hier findet sich eine nette visuelle Einführung.
Es finden sich viele Tutorials online zu Joins. Dieses ist ein empfehlenswertes.
5.1 Erster Versuch
d <-
d_str2 %>%
full_join(elec_results2, by = c("area_name" = "Gebietsname"))Einige Zeilen lassen sich nicht zusammenführen. Schauen wir diese uns näher an:
d %>%
filter(str_detect(area_name, "nsgesamt")) # Ohne "I"!## # A tibble: 17 × 17
## state area_nr area_name for_prop pop_density pop_move income unemp Gebietsart
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Schl… 901 Land ins… 8.4 184. 6 22833 6.3 <NA>
## 2 Meck… 913 Land ins… 4.7 69 5 19470 8.7 <NA>
## 3 Hamb… 902 Land ins… 16.5 2446. 2.7 25029 8.1 <NA>
## 4 Nied… 903 Land ins… 9.7 168. 4.4 21988 6.1 <NA>
## 5 Brem… 904 Land ins… 18.5 1624. -1.1 21481 11.6 <NA>
## 6 Bran… 912 Land ins… 5 85 9.1 20475 6.6 <NA>
## 7 Sach… 915 Land ins… 5.1 107. 1.1 19528 8.3 <NA>
## 8 Berl… 911 Land ins… 19.2 4118. 6.3 20972 10.6 <NA>
## 9 Nord… 905 Land ins… 13.6 526. 2.6 22294 7.9 <NA>
## 10 Sach… 914 Land ins… 5.1 221. 3.8 20335 6.6 <NA>
## 11 Hess… 906 Land ins… 16.6 298. 4.5 23943 5.7 <NA>
## 12 Thür… 916 Land ins… 5.2 132. 1.6 19793 6.4 <NA>
## 13 Rhei… 907 Land ins… 11.5 206. 5 23197 5.6 <NA>
## 14 Baye… 909 Land ins… 13.6 186. 4.5 25309 4.2 <NA>
## 15 Bade… 908 Land ins… 15.9 310. 3.4 24892 4.4 <NA>
## 16 Saar… 910 Land ins… 11.4 384. 2.2 20277 7.4 <NA>
## 17 Deut… 999 Insgesamt 12.5 233. 3.9 22899 6.3 <NA>
## # … with 8 more variables: Gebietsnummer <chr>, UegGebietsart <chr>,
## # UegGebietsnummer <chr>, Gruppenart <chr>, Gruppenname <chr>, Stimme <dbl>,
## # Prozent <dbl>, DiffProzentPkt <dbl>
Es sind die Bundesländer, deren area_name “Land insgesamt”, jeweils, lautet.
Diese Felder müssen wir wohl umbenennen.
Bundesländer - plus der Bund als Ganzes - haben eine ID, die mit 9 beginnt, was für sonstige Einheiten nicht der Fall ist:
d_leander <-
d %>%
select(area_nr, area_name, state) %>%
filter(str_detect(area_nr, "^9")) %>%
mutate(area_name = state) %>%
select(-state)Da die Länder auch noch noch eine andere Gebietsnummer haben in der Datei mit den Strukturdaten, fügen wir noch die Gebietsnummer aus elec_results2 hinzu:
d_laender2 <-
d_leander %>%
left_join(elec_results2 %>% select(Gebietsname, Gebietsnummer), by = c("area_name" = "Gebietsname"))Sieht dann so aus:
d_laender2## # A tibble: 17 × 3
## area_nr area_name Gebietsnummer
## <chr> <chr> <chr>
## 1 901 Schleswig-Holstein 01
## 2 913 Mecklenburg-Vorpommern 13
## 3 902 Hamburg 02
## 4 903 Niedersachsen 03
## 5 904 Bremen 04
## 6 912 Brandenburg 12
## 7 915 Sachsen-Anhalt 15
## 8 911 Berlin 11
## 9 905 Nordrhein-Westfalen 05
## 10 914 Sachsen 14
## 11 906 Hessen 06
## 12 916 Thüringen 16
## 13 907 Rheinland-Pfalz 07
## 14 909 Bayern 09
## 15 908 Baden-Württemberg 08
## 16 910 Saarland 10
## 17 999 Deutschland 99
5.2 Zweiter Versuch
Jetzt fügen wir die korrigierten Landesnamen und -nummern zu d_str2 hinzu:
d_str3 <-
d_str2 %>%
left_join(d_laender2, by = "area_nr")area_name.y ist aktuell nur mit Landesnamen (plus Bund) gefüllt. Ergänzen wir also die NAs mit den Namen der Wahlbezirke. Die andere Spalte area_name.x brauchen wir dann nicht mehr.
d_str4 <-
d_str3 %>%
mutate(area_name.y = ifelse(is.na(area_name.y),
area_name.x,
area_name.y)) %>%
select(-area_name.x) %>%
rename(area_name = area_name.y)Das Gleiche machen wir mit area_nr:
d_str5 <-
d_str4 %>%
mutate(area_nr = ifelse(is.na(Gebietsnummer),
area_nr,
Gebietsnummer))d_str5 %>%
slice_head(n=20) ## # A tibble: 20 × 9
## state area_nr for_prop pop_density pop_move income unemp area_name
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Schlesw… 001 8.4 137. 9.5 21358 7 Flensburg – Schl…
## 2 Schlesw… 002 7.1 84.6 8.3 24354 6.5 Nordfriesland – …
## 3 Schlesw… 003 6.5 110. 4.6 22292 6.4 Steinburg – Dith…
## 4 Schlesw… 004 5.5 116. 8.6 23410 4.8 Rendsburg-Eckern…
## 5 Schlesw… 005 11.4 1879. -1.8 19718 8.4 Kiel
## 6 Schlesw… 006 8.7 171. 5.1 22081 6.7 Plön – Neumünster
## 7 Schlesw… 007 11.1 476. 8.1 24708 5.9 Pinneberg
## 8 Schlesw… 008 8 240. 5.7 23952 5 Segeberg – Storm…
## 9 Schlesw… 009 5.7 144. 6.8 23411 6.1 Ostholstein – St…
## 10 Schlesw… 010 8.6 237. 8.8 24571 5.1 Herzogtum Lauenb…
## 11 Schlesw… 011 10 580 1.3 20404 8.5 Lübeck
## 12 Schlesw… 01 8.4 184. 6 22833 6.3 Schleswig-Holste…
## 13 Mecklen… 012 6.7 73.9 2.6 19927 8 Schwerin – Ludwi…
## 14 Mecklen… 013 4 63.3 7.5 20014 6.8 Ludwigslust-Parc…
## 15 Mecklen… 014 5.5 278 6 19274 7.9 Rostock – Landkr…
## 16 Mecklen… 015 4.7 84.7 6.7 19231 11 Vorpommern-Rügen…
## 17 Mecklen… 016 3.8 53.8 2.8 18774 9.9 Mecklenburgische…
## 18 Mecklen… 017 3 40 4.2 19679 8.5 Mecklenburgische…
## 19 Mecklen… 13 4.7 69 5 19470 8.7 Mecklenburg-Vorp…
## 20 Hamburg 018 21.8 3044. 2.7 25029 8.1 Hamburg-Mitte
## # … with 1 more variable: Gebietsnummer <chr>
Scheint zu passen.
d <-
d_str5 %>%
left_join(elec_results2, by = c("area_nr" = "Gebietsnummer"))dim(d)## [1] 316 18
316 ist eine gute Zahl:
- 299 Wahlbezirke +
- 16 Länder +
- 1 Bund
ergibt 316.
5.3 Check
Prüfen wir, ob es noch fehlende Werte nach dem Join gibt:
d %>%
filter(is.na(Gruppenname), is.na(Prozent)) %>%
select(area_name, area_nr, Prozent) %>%
nrow()## [1] 0
Zählen wir die Anzahl der Wahleinheiten nach Art:
d %>%
group_by(Gebietsart) %>%
count()## # A tibble: 3 × 2
## # Groups: Gebietsart [3]
## Gebietsart n
## <chr> <int>
## 1 Bund 1
## 2 Land 16
## 3 Wahlkreis 299
Das sieht gut aus.
5.4 Geo-Daten
Die Geodaten sind ebenfalls erhältlich beim Bundeswahlleiter.
Ich habe diese Version verwendet: “Geometrie der Wahlkreise im Koordinatensystem UTM32”, generalisierte Shape-Datei.
Die Geodaten zur Visualisierung der Wahlkreise werden im sog. “Shape-Format” (.shp) geliefert.
geo_file <- "data/btw21_geometrie_wahlkreise_shp/Geometrie_Wahlkreise_20DBT.shp"Einlesen:
wahlkreise_shp <- st_read(geo_file)## Reading layer `Geometrie_Wahlkreise_20DBT' from data source
## `/Users/sebastiansaueruser/github-repos/afd-btw21-analyse/data/btw21_geometrie_wahlkreise_shp/Geometrie_Wahlkreise_20DBT.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 299 features and 4 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 280371.1 ymin: 5235856 xmax: 921120.1 ymax: 6101444
## Projected CRS: ETRS89 / UTM zone 32N
Hilfe zu st_read() findet sich hier oder auf der Dokumentation zum R-Paket sf (simple feature).
Plotten:
wahlkreise_shp %>%
ggplot() +
geom_sf()Hilfe zum Geom sf (simple feature) findet sich hier.
Man beachte die Installationshinweise.
Der Aufbau des Datensatzes ist aufgeräumt:
glimpse(wahlkreise_shp)## Rows: 299
## Columns: 5
## $ WKR_NR <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 1…
## $ WKR_NAME <chr> "Flensburg – Schleswig", "Nordfriesland – Dithmarschen Nord"…
## $ LAND_NR <chr> "01", "01", "01", "01", "01", "01", "01", "01", "01", "01", …
## $ LAND_NAME <chr> "Schleswig-Holstein", "Schleswig-Holstein", "Schleswig-Holst…
## $ geometry <MULTIPOLYGON [m]> MULTIPOLYGON (((545529.8 60..., MULTIPOLYGON ((…
5.5 Geo-Daten joinen
d2 <-
d %>%
mutate(area_nr = as.integer(area_nr)) %>%
full_join(wahlkreise_shp, by = c("area_nr" = "WKR_NR"))6 Geo-Vis
6.1 AfD-Anteil
d2 %>%
ggplot() +
geom_sf(aes(fill = Prozent,
geometry = geometry))Verschönern:
d2 %>%
ggplot() +
geom_sf(aes(fill = Prozent,
geometry = geometry),
color = NA) +
scale_fill_viridis_c() +
theme_void() +
labs(title = "Anteil der Zweitstimmen für die AfD",
subtitle = "Bundestagswahl 2021",
fill = "Anteil AfD-Zweitstimmen") +
theme(legend.position = "bottom")Ein paar Wahlkreise haben entweder nicht erwischt, oder es gibt keine Daten.
6.2 Ausländeranteil
d2 %>%
ggplot() +
geom_sf(aes(fill = for_prop,
geometry = geometry),
color = NA) +
scale_fill_viridis_c() +
theme_void()6.3 Arbeitslosigkeit
d2 %>%
ggplot() +
geom_sf(aes(fill = unemp,
geometry = geometry),
color = NA) +
scale_fill_viridis_c() +
theme_void()6.4 Bevölkerungsdichte
d2 %>%
ggplot() +
geom_sf(aes(fill = pop_density,
geometry = geometry),
color = NA) +
scale_fill_viridis_c() +
theme_void()Oder vielleicht lieber Bevölkerungsdichte in der Log2-Skala?
d2 %>%
ggplot() +
geom_sf(aes(fill = log2(pop_density),
geometry = geometry),
color = NA) +
scale_fill_viridis_c() +
theme_void()So kommen die Unterschiede optisch deutlich besser zum Tragen.
Zur Erinnerung: +1 auf der Log2-Skala entspricht einer Multiplikation mit 2 auf der Rohskala. Die Log2-Skala zählt also “Verdopplungsschritte”.
7 EDA
7.1 Prädiktoren des AfD-Wahlerfolgs
7.1.1 Ausländeranteil
d2 %>%
filter(Gebietsart == "Wahlkreis") %>%
select(Prozent, for_prop) %>%
ggplot() +
aes(x = for_prop, y = Prozent) +
geom_point(alpha = .7) +
geom_smooth()Interessant! Ein einfacher linearer Trend liegt nicht vor. Vielleicht sehen wir eher zwei, unterschiedliche Cluster?
Cluster 1 ist geprägt von hohem Ausländeranteil und Cluster 2 von geringem. In beiden Clustern ist der Zusammenhang negativ. Allerdings ist dieser Zusammenhang deutlich stärker ausgeprägt für Cluster 1.
7.1.2 Ausländeranteil nach Bundesland
Wenn wir diese Analyse aufteilen nach Bundesländern, sehen wir vielleicht klarer.
d2 %>%
filter(Gebietsart == "Wahlkreis") %>%
select(Prozent, for_prop, state) %>%
ggplot() +
aes(x = for_prop, y = Prozent, color = state) +
geom_point(alpha = .7) +
geom_smooth(method = "lm") +
facet_wrap(~ state) +
scale_y_continuous(limits = c(0, 40)) +
theme(legend.position = "none")Es scheint sich in jedem Bundesland ein negativer, linearer Zusammenhang zu zeigen. Es sei denn, der AfD-Anteil ist sehr gering, dann wird der Zusammenhang schwach, also eine Bodeneffekt.
7.2 Bivariate Korrelationen
d2 %>%
select(Prozent, for_prop, unemp, income, pop_density) %>%
cor_mat()## # A tibble: 5 × 6
## rowname Prozent for_prop unemp income pop_density
## * <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Prozent 1 -0.58 0.038 -0.44 -0.3
## 2 for_prop -0.58 1 0.23 0.38 0.65
## 3 unemp 0.038 0.23 1 -0.56 0.51
## 4 income -0.44 0.38 -0.56 1 0.046
## 5 pop_density -0.3 0.65 0.51 0.046 1
d2 %>%
select(Prozent, for_prop, unemp, income, pop_density) %>%
cor_mat() %>%
cor_plot()Das Kreuz zeigt wohl eine Korrelation nahe Null an.
Die Korrelationsmatrix im langen Format:
d2 %>%
select(Prozent, for_prop, unemp, income, pop_density) %>%
cor_mat() %>%
cor_gather() %>%
filter(cor != 1) %>%
filter(var1 == "Prozent") %>%
arrange(cor) %>%
gt() %>%
fmt_number(where(is.numeric), decimals = 2)| var1 | var2 | cor | p |
|---|---|---|---|
| Prozent | for_prop | −0.58 | 0.00 |
| Prozent | income | −0.44 | 0.00 |
| Prozent | pop_density | −0.30 | 0.00 |
| Prozent | unemp | 0.04 | 0.50 |
Je mehr Ausländer, oder auch je mehr Einkommen, desto weniger wird AfD gewählt. Die Arbeitslosigkeit steht fast nicht in einem (linearen) Zusammenhang mit dem AfD-Wahlerfolg.
8 Modellierung
8.1 Daten aufbereiten
Alle Prozessorkerne nutzen:
options(mc.cores = parallel::detectCores())Die kompilierten Modelle auf die Hard Disk schreiben, das geht schneller, als jedes Mal neu zu berechnen:
rstan::rstan_options(auto_write = TRUE)Alternativ könnte man das Ergebnisobjekt, wie m1 mit save(m1, file = "m1.rda") in eine Datei speichern.
Daten aufbereiten, d.h. z-standardisieren:
d3 <-
d2 %>%
mutate(Prozent_z = scale(Prozent),
for_prop_z = scale(for_prop),
unemp_z = scale(unemp)) %>%
select(Prozent_z, state, for_prop_z, unemp_z, Gebietsname) %>%
filter(state != "Deutschland")Wir nutzen z-Werte als AV; das hat auch pragmatische Gründe: z-Werte sind kontinuierlich und unbegrenzt und daher angenehm mit linearen Modellen zu untersuchen.
8.2 Modellkaskade
In der Forschungsfrage 2 untersuchen wir sozioökonomische Faktoren. Diese werden in den ersten Modellen analysiert.
Die Frage nach dem uniquen Erklärungsbeitrag der Bundesländer wird in Forschungsfrage 3 gestellt. Entsprechend werden Modelle aufgestellt, die den spezifischen Erklärungsbeitrag der Bundesländer (hinsichtlich der AV) untersuchen.
8.3 Ergebnisobjekt
In diesem Tibble (Dataframe, Tabelle) speichern wir zentrale Ergebnisse des Modells:
results <-
tibble(
model_id = NA,
priors = "standard",
preds = NA,
r2 = NA,
r2_loo = NA,
coefs = NA
)8.4 Model 1: Arbeitslosigkeit
In diesem Modell wird der AfD-Wahlerfolg auf die Arbeitslosigkeit zurückgeführt.
8.4.1 Modell berechnen
tic()
m1 <- stan_glm(Prozent_z ~ unemp_z,
data = d3,
refresh = 0)
toc()## 1.978 sec elapsed
8.4.2 Ergebnis
m1## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ unemp_z
## observations: 315
## predictors: 2
## ------
## Median MAD_SD
## (Intercept) 0.0 0.1
## unemp_z 0.0 0.1
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 1.0 0.0
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
Oder kürzer:
coef(m1)## (Intercept) unemp_z
## -8.329159e-05 3.733159e-02
Wie man sieht, spielt die Arbeitslosigkeit keine Rolle zur Erklärung des AfD-Wahlerfolgs.
plot(m1)Man kann sich auch andere Darstellungen der Posteriori-Verteilung zeigen lassen:
mcmc_areas_ridges(m1,
pars = "unemp_z")Offensichtlich kann es nicht ausgeschlossen werden, dass die Arbeitslosigkeit unabhängig vom AfD-Wahlerfolg ist.
8.4.3 Modellprüfung
8.4.3.1 PPV
pp_check(m1)Oh, unser Modell erklärt die Daten schlecht.
tibble(
resid = resid(m1),
pred = predict(m1)
) %>%
ggplot() +
aes(x = pred, y = resid) +
geom_hline(yintercept = 0, linetype = "dotted") +
geom_point() +
geom_smooth()Die Varianz ist nicht homogen über die Prädiktorwerte hinweg. Außerdem finden sich Anzeichen eines nichtlinearen Trends.
8.4.4 Prioris
prior_summary(m1)## Priors for model 'm1'
## ------
## Intercept (after predictors centered)
## Specified prior:
## ~ normal(location = 0.00014, scale = 2.5)
## Adjusted prior:
## ~ normal(location = 0.00014, scale = 2.5)
##
## Coefficients
## Specified prior:
## ~ normal(location = 0, scale = 2.5)
## Adjusted prior:
## ~ normal(location = 0, scale = 2.5)
##
## Auxiliary (sigma)
## Specified prior:
## ~ exponential(rate = 1)
## Adjusted prior:
## ~ exponential(rate = 1)
## ------
## See help('prior_summary.stanreg') for more details
tic()
m1_prior_pv <- stan_glm(Prozent_z ~ unemp_z,
data = d3,
prior_PD = TRUE,
refresh = 0)
toc()## 1.619 sec elapsed
Hinweise zu prior_PD finden sich hier.
coef(m1_prior_pv)## (Intercept) unemp_z
## 0.04892458 0.02111651
plot(m1_prior_pv)Die Prioris sehen vernünftig aus.
Vergleich der Priori-Verteilung mit der Post-Verteilung:
posterior_vs_prior(m1)8.4.5 Fazit
m1_results <-
tibble(
model_id = "m1",
priors = "standard",
preds = "unemp_z",
r2 = median(m1_r2),
r2_loo = median(m1_loo_r2),
coefs = list(coef(m1))
)results <-
results %>%
bind_rows(m1_results)8.5 Modell 2: Ausländeranteil
8.5.1 Modell berechnen (m2)
tic()
m2 <-
stan_glm(Prozent_z ~ for_prop_z,
data = d3,
refresh = 0
)
toc()## 1.986 sec elapsed
8.5.2 Ergebnis
m2## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ for_prop_z
## observations: 315
## predictors: 2
## ------
## Median MAD_SD
## (Intercept) 0.0 0.0
## for_prop_z -0.6 0.0
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 0.8 0.0
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
Modellparameter visualisieren:
plot(m2)mcmc_areas(m2,
pars = "for_prop_z")Der Ausländeranteil spielt laut unserem Modell eine große Rolle.
8.5.2.1 R2
m2_r2 <- bayes_R2(m2)
median(m2_r2)## [1] 0.333135
8.5.3 Modellprüfung
8.5.3.1 PPV
pp_check(m2)Unser Modell erklärt die Daten nicht gut.
8.5.3.2 Kreuzvalidierung
m2_loo_r2 <- loo_R2(m2)
median(m2_loo_r2)## [1] 0.3276684
8.5.4 Prioris
tic()
m2_prior_pd <-
stan_glm(Prozent_z ~ for_prop_z,
data = d3,
prior_PD = TRUE,
refresh = 0
)
toc()## 1.305 sec elapsed
m2_prior_pd## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ for_prop_z
## observations: 315
## predictors: 2
## ------
## Median MAD_SD
## (Intercept) 0.0 2.4
## for_prop_z 0.0 2.5
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 0.7 0.7
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
plot(m2_prior_pd,
pars = "for_prop_z")8.5.5 Fazit
m2_results <-
tibble(
model_id = "m2",
priors = "standard",
preds = "for_prop_z",
r2 = median(m2_r2),
r2_loo = median(m2_loo_r2),
coefs = list(coef(m2))
)results <-
results %>%
bind_rows(m2_results)8.6 Modell 3: Arbeitslosigkeit und Ausländeranteil
8.6.1 Modell berechnen (m3)
tic()
m3 <-
stan_glm(Prozent_z ~ for_prop_z + unemp_z,
data = d3,
refresh = 0
)
toc()## 2.062 sec elapsed
8.6.2 Ergebnis
m3## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ for_prop_z + unemp_z
## observations: 315
## predictors: 3
## ------
## Median MAD_SD
## (Intercept) 0.0 0.0
## for_prop_z -0.6 0.0
## unemp_z 0.2 0.0
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 0.8 0.0
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
Interessant. Zusätzlich zum Ausländeranteil spielt die Arbeitslosigkeit jetzt doch eine Rolle: Es findet sich jetzt eine positive Assoziation mit der AV.
plot(m3, plotfun = "mcmc_dens")Details zu plot() im Zusammenhang von rstanarm finden sich hier.
8.6.2.1 R2
m3_r2 <- bayes_R2(m3)
median(m3_r2)## [1] 0.3643387
m3_loo_r2 <- loo_R2(m3)
median(m3_loo_r2)## [1] 0.3544175
8.6.3 Modellprüfung
pp_check(m3)Hm, auch dieses Modell erklärt die Daten nicht gut.
8.6.4 Fazit
m3_results <-
tibble(
model_id = "m3",
priors = "standard",
preds = "unemp_z + for_prop_z",
r2 = median(m2_r2),
r2_loo = median(m2_loo_r2),
coefs = list(coef(m2))
)results <-
results %>%
bind_rows(m3_results)8.7 Modell 4: Bundesländer
Frühere Analysen haben gezeigt, dass die Bundesländer über sozioökonomische Faktoren hinaus eine hohe prädiktive Relevanz in den Modellen haben.
8.7.1 Modell berechnen (m4)
tic()
m4 <-
stan_glm(Prozent_z ~ state,
data = d3,
refresh = 0
)
toc()## 2.198 sec elapsed
8.7.2 Ergebnis
m4## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ state
## observations: 315
## predictors: 16
## ------
## Median MAD_SD
## (Intercept) -0.2 0.1
## stateBayern -0.1 0.1
## stateBerlin -0.2 0.1
## stateBrandenburg 1.5 0.2
## stateBremen -0.4 0.3
## stateHamburg -0.8 0.2
## stateHessen -0.1 0.1
## stateMecklenburg-Vorpommern 1.4 0.2
## stateNiedersachsen -0.4 0.1
## stateNordrhein-Westfalen -0.4 0.1
## stateRheinland-Pfalz -0.1 0.1
## stateSaarland 0.1 0.2
## stateSachsen 2.6 0.1
## stateSachsen-Anhalt 1.7 0.2
## stateSchleswig-Holstein -0.5 0.2
## stateThüringen 2.4 0.2
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 0.5 0.0
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
plot(m4, regex_pars = "^state")Sachsen und Thüringen haben die stärksten (absoluten und positiven) Koeffizienten.
m4_r2 <- bayes_R2(m4)
m4_r2_loo <- loo_R2(m4)8.8 Modell 5: Sachsen und Thüringen vs. Rest
d4 <-
d3 %>%
mutate(Sachsen_Thueringen = case_when(
state == "Sachsen" | state == "Thüringen" ~ 1,
TRUE ~ 0
)) %>%
select(-state)8.8.1 Modell berechnen (m5)
tic()
m5 <-
stan_glm(Prozent_z ~ Sachsen_Thueringen,
data = d4,
refresh = 0
)
toc()## 1.383 sec elapsed
8.8.2 Ergebnisse
m5## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ Sachsen_Thueringen
## observations: 315
## predictors: 2
## ------
## Median MAD_SD
## (Intercept) -0.2 0.0
## Sachsen_Thueringen 2.6 0.1
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 0.7 0.0
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
plot(m5, pars = "Sachsen_Thueringen")Das ist ein sehr starker Effekt.
m5_r2 <- bayes_R2(m5)
m5_r2_loo <- loo_R2(m5)8.9 Modell 6: Alle Prädiktoren
8.9.1 Modell berechnen (m6)
tic()
m6 <-
stan_glm(Prozent_z ~ state + for_prop_z + unemp_z,
data = d3,
refresh = 0
)
toc()## 2.074 sec elapsed
8.9.2 Ergebnisse
m6## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ state + for_prop_z + unemp_z
## observations: 315
## predictors: 18
## ------
## Median MAD_SD
## (Intercept) 0.3 0.1
## stateBayern -0.2 0.1
## stateBerlin -0.6 0.2
## stateBrandenburg 0.6 0.2
## stateBremen -1.0 0.3
## stateHamburg -1.1 0.2
## stateHessen -0.2 0.1
## stateMecklenburg-Vorpommern 0.3 0.2
## stateNiedersachsen -0.9 0.1
## stateNordrhein-Westfalen -0.9 0.1
## stateRheinland-Pfalz -0.4 0.1
## stateSaarland -0.5 0.2
## stateSachsen 1.7 0.2
## stateSachsen-Anhalt 0.7 0.2
## stateSchleswig-Holstein -1.1 0.2
## stateThüringen 1.6 0.2
## for_prop_z -0.3 0.0
## unemp_z 0.2 0.0
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 0.4 0.0
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
m6_r2 <- bayes_R2(m6)
m6_r2_loo <- loo_R2(m6)
median(m6_r2_loo)## [1] 0.8220622
8.9.3 Modellprüfung
pp_check(m6)Das Modell erklärt die Daten gut.
8.10 Modell 7: Ausländer, Arbeitslosigkeit, Sachsen-Thüringen
8.10.1 Modell berechnen (m7)
tic()
m7 <-
stan_glm(Prozent_z ~ Sachsen_Thueringen + for_prop_z + unemp_z,
data = d4,
refresh = 0
)
toc()## 1.547 sec elapsed
8.10.2 Ergebnisse
m7## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ Sachsen_Thueringen + for_prop_z + unemp_z
## observations: 315
## predictors: 4
## ------
## Median MAD_SD
## (Intercept) -0.2 0.0
## Sachsen_Thueringen 2.1 0.1
## for_prop_z -0.4 0.0
## unemp_z 0.1 0.0
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 0.6 0.0
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
m7_r2 <- bayes_R2(m7)
m7_r2_loo <- loo_R2(m7)
median(m7_r2_loo)## [1] 0.627569
8.11 Modell 8: Nur Sachsen-Thüringen
8.11.1 Modell berechnen (m8)
tic()
m8 <-
stan_glm(Prozent_z ~ Sachsen_Thueringen,
data = d4,
refresh = 0
)
toc()## 1.479 sec elapsed
8.11.2 Ergebnisse
m8## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ Sachsen_Thueringen
## observations: 315
## predictors: 2
## ------
## Median MAD_SD
## (Intercept) -0.2 0.0
## Sachsen_Thueringen 2.6 0.1
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 0.7 0.0
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
m8_r2 <- bayes_R2(m8)
m8_r2_loo <- loo_R2(m8)
median(m8_r2_loo)## [1] 0.5002692
8.12 Modell 9: Sachsen-Thüringen und Ausländer
8.12.1 Modell berechnen (m8)
tic()
m9 <-
stan_glm(Prozent_z ~ Sachsen_Thueringen + for_prop_z,
data = d4,
refresh = 0
)
toc()## 1.41 sec elapsed
8.12.2 Ergebnisse
m9## stan_glm
## family: gaussian [identity]
## formula: Prozent_z ~ Sachsen_Thueringen + for_prop_z
## observations: 315
## predictors: 3
## ------
## Median MAD_SD
## (Intercept) -0.2 0.0
## Sachsen_Thueringen 2.1 0.1
## for_prop_z -0.4 0.0
##
## Auxiliary parameter(s):
## Median MAD_SD
## sigma 0.6 0.0
##
## ------
## * For help interpreting the printed output see ?print.stanreg
## * For info on the priors used see ?prior_summary.stanreg
m9_r2 <- bayes_R2(m9)
m9_r2_loo <- loo_R2(m9)
median(m9_r2_loo)## [1] 0.616266
8.12.3 Visualisierung
Es lohnt sich vielleicht, dieses Modell zu visualisieren.
m9_draws <-
m9 %>%
as_tibble() %>%
rename(intercept = `(Intercept)`) %>%
dplyr::select(-sigma)ggplot(d4) +
aes(x = for_prop_z, y = Prozent_z) +
# Ungewissheit der Regressionsgeraden:
geom_abline(
aes(intercept = intercept, slope = for_prop_z),
data = sample_n(m9_draws, 100),
color = "grey60",
alpha = .15
) +
# Mediane Schätzwerte für "die" Regressionsgerade:
geom_abline(
intercept = median(m9_draws$intercept),
slope = median(m9_draws$for_prop_z),
size = 1,
color = "blue"
) +
geom_point()8.13 Modelle vergleichen
loo_m1 <- loo(m1)
loo_m2 <- loo(m2)
loo_m3 <- loo(m3)
loo_m4 <- loo(m4)
loo_m5 <- loo(m5)
loo_m6 <- loo(m6, k_threshold = 0.7)
loo_m7 <- loo(m7)
loo_m8 <- loo(m8)
loo_m9 <- loo(m9)loo_comparison <-
loo_compare(
loo_m1,
loo_m2,
loo_m3,
loo_m4,
loo_m5,
loo_m6,
loo_m7,
loo_m8,
loo_m9
)
loo_comparison ## elpd_diff se_diff
## m6 0.0 0.0
## m4 -36.5 7.9
## m7 -113.6 18.2
## m9 -118.4 19.4
## m5 -160.5 22.4
## m8 -160.6 22.4
## m3 -201.4 23.7
## m2 -208.0 23.6
## m1 -272.0 25.5
Bestes Modell:
loo_min_model <-
attr(loo_comparison, "dimnames")[[1]][1]
loo_min_model## [1] "m6"
Hilfe zum Vergleich des LOO-Werte findet sich hier.
Modell m6 tat sich als bestes Modell hervor.
9 Fazit
9.1 Fazit der Modellierung
Modell m7 kam als bestes Modell im Vergleich hervor.
9.2 Interpretation
Zwar spielen die sozioökonomischen Kennwerte eine Rolle, aber ein wichtiger Faktor zur Vorhersage des Wahlerfolg sind die Bundesländer. Dabei sticht das Duo Thüringen-Sachsen hervor. Diese beiden Bundesländer haben - über den Beitrag der sozioökonomischen Kennwerte hinaus - einen besonders großen Beitrag zur Erklärung der AfD-Wahlergebnisse.
Das Modell schickt uns damit gleichsam zurück an den Schreibtisch: Wir brauchen eine Theorie, die erklären könnte, warum gerade die Bundesländer und gerade bestimmte Bundesländer Informationen in sich bergen, die den AfD-Wahlerfolg besonders gut erklären können.
Die Frage nach dem “warum” ist eine kausale; wissenschaftliche (und sonstige!) Theorien sind zumeist an den kausalen Abhängigkeiten interessiert. Das hat auch praktische Gründe: Nur, wenn man das “warum” kennt, kann man Interventionen einleiten; sonst wüsste man nicht, welche Interventionen bei welchen Variablen welchen Nutzen haben.
9.3 Ausblick
In Mehrebenenmodell wäre noch ein sinnvolle Erweiterung.